package dfw

import (
	"bufio"
	"dfws/rsa"
	"log"
	"net"
	"strconv"
	"strings"
	"time"
)

func StartServer(workDir string, host string, port int, timeout int) {
	if port > 65535 || port < 1 {
		port = 6760
	}
	if host == "" {
		host = "0.0.0.0"
	}
	address := host + ":" + strconv.Itoa(port)
	/**
	  使用Listen函数创建监听socket,其函数签名如下:
	      func Listen(network, address string) (Listener, error)
	  以下是对函数签名的参数说明:
	      network:
	          指定服务端socket的协议,如tcp/udp,注意是小写字母哟~
	      address:
	          指定服务端监听的IP地址和端口号,如果不指定地址默认监听当前服务器所有IP地址哟~
	*/
	socket, err := net.Listen("tcp", address)
	if err != nil {
		log.Fatalf("开启服务失败,错误原因: ", err, address)
		return
	}
	defer socket.Close()
	log.Println("开启服务...", address, "workdir:", workDir)

	//接收多个用户
	for {
		/**
		  等待客户端连接请求
		*/
		conn, err := socket.Accept()
		if err != nil {
			log.Println("建立链接失败,错误原因: ", err)
			return
		}

		//处理用户请求, 新建一个go程
		go HandleConn(conn, timeout, workDir)
	}
}

func HandleConn(conn net.Conn, timeout int, workDir string) {
	//函数调用完毕，自动关闭conn
	defer conn.Close()

	//获取客户端的网络地址信息
	addr := conn.RemoteAddr().String()
	log.Println(addr, " connect success")
	reader := bufio.NewReader(conn)
	for {
		if timeout > 0 {
			conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
		}
		//读取数据
		netDataRequest, err := UnPack(reader)
		if err != nil {
			log.Println(`解包数据 error :`, err)
			return
		}
		//加载私钥
		if err := rsa.LoadPrivateKey(workDir, netDataRequest.Id); err != nil {
			log.Println(`加载秘钥错误 error :`, err)
			return
		}
		//解密数据
		data, err := rsa.RSA.PriKeyDECRYPT(netDataRequest.Data)
		if err != nil {
			log.Println(`解密请求 error :`, err)
			return
		}

		log.Println(`数据:`, string(data))

		info, err := SetFwConfig(workDir, netDataRequest.Id, strings.Split(string(data), ","))

		//加密数据
		result, err := rsa.RSA.PriKeyENCTYPT([]byte(info))

		if err != nil {
			log.Println(`加密响应数据 error :`, err)
			return
		}
		netDataResponse := NetData{
			Id:     netDataRequest.Id,
			Data:   result,
			Action: []byte("msg"),
		}

		packetData, err := Packet(netDataResponse)
		if err != nil {
			log.Println(`封装响应数据 error :`, err)
			return
		}
		if timeout > 0 {
			conn.SetWriteDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
		}
		conn.Write(packetData)
		return
	}
}
